﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;

public class FormGamePlay : Form
{
    private const int k_SpaceInRowBetweenButtons = 6;
    private const int k_SpaceInColBetweenButtons = 6;
    private const int k_FirstPlayerIndex = 1;
    private const int k_SecondPlayerIndex = 2;
    private const int k_Left = 12;
    private const char k_X = 'X';
    private readonly List<ColumnNumberedButton> r_ColumnNumberedButtonsList = null;
    private readonly BoardButton[,] r_BoardButtonsArray = null;
    private int m_BoardViewRowSize = 0;
    private int m_BoardViewColSize = 0;
    private GameEngine.eGameMoveStatus m_CurrentGameStatus = GameEngine.eGameMoveStatus.Continue;
    private GameEngine.ePlayerIndex m_CurrentPlayerIndex = GameEngine.ePlayerIndex.FirstPlayer;
    private GameEngine m_GameEngine = null;
    private bool m_IsTwoUserPlayers = false;
    private Label LabelPlayer2;
    private Label LabelPlayer2Score;
    private Label LabelPlayer1Score;
    private Label LabelPlayer1;

    public FormGamePlay(int i_RowSize, int i_ColSize, bool i_IsTwoPlayers, string i_FirstPlayerName, string i_SecondPlayerName)
    {
        this.m_BoardViewColSize = i_ColSize;
        this.m_BoardViewRowSize = i_RowSize;
        this.m_IsTwoUserPlayers = i_IsTwoPlayers;

        this.m_GameEngine = new GameEngine(this.m_BoardViewRowSize, this.m_BoardViewColSize, this.m_IsTwoUserPlayers);
        this.r_ColumnNumberedButtonsList = new List<ColumnNumberedButton>(i_ColSize);
        this.r_BoardButtonsArray = new BoardButton[i_RowSize, i_ColSize];

        this.initializeBoardButtonsEventHandlers();
        this.initializePlayersEventHandlers();

        this.loadColsButtons(this.m_BoardViewColSize);
        this.loadBoardButtons(this.m_BoardViewRowSize, this.m_BoardViewColSize);

        this.setClientSize();
        this.setScoreBoardSize();
        this.initializeComponent();
        this.LabelPlayer1.Text = i_FirstPlayerName + ":";
        this.LabelPlayer2.Text = i_SecondPlayerName + ":";
        this.LabelPlayer1Score.Left = this.LabelPlayer1.Left + this.LabelPlayer1.Width;
        this.LabelPlayer2Score.Left = this.LabelPlayer2.Left + this.LabelPlayer2.Width;
    }

    private void initializeBoardButtonsEventHandlers()
    {
        Cell[,] arr = this.m_GameEngine.BoardMatrix;

        foreach (Cell item in arr)
        {
            item.CellChange += new CellChangeDelegate(this.Cell_Change);
        }
    }

    private void initializePlayersEventHandlers()
    {
        this.m_GameEngine.GetPlayerByIndex(0).ScoreChange += new ScoreChangeDelegate(this.OnScoreChange);
        this.m_GameEngine.GetPlayerByIndex(1).ScoreChange += new ScoreChangeDelegate(this.OnScoreChange);
    }

    public void OnScoreChange(object i_Obj)
    {
        Player CurrentPlayer = i_Obj as Player;

        if (CurrentPlayer.PlayerSymbol.Equals(k_X))
        {
            this.LabelPlayer1Score.Text = CurrentPlayer.Score.ToString();
        }
        else
        {
            this.LabelPlayer2Score.Text = CurrentPlayer.Score.ToString();
        }
    }

    public void Cell_Change(object i_Obj)
    {
        Cell CurrentCell = i_Obj as Cell;
        BoardButton CurrentBoardButton = this.r_BoardButtonsArray[CurrentCell.R_RowIndex, CurrentCell.R_ColIndex];
        CurrentBoardButton.Text = CurrentCell.ToString();
    }

    public enum eErrorMessage
    {
        ColumnIsFull = 0,
        InvalidBoardSize,
        InvalidGameMode,
        InvalidKeyPressed,
        BoardIsFull
    }

    private void setClientSize()
    {
        int height = this.r_ColumnNumberedButtonsList[0].Height + ((this.r_BoardButtonsArray[0, 0].Height + k_SpaceInRowBetweenButtons) * this.m_BoardViewRowSize);
        height += this.r_BoardButtonsArray[0, 0].Height + k_SpaceInRowBetweenButtons;
        int width = (this.r_ColumnNumberedButtonsList[0].Width + k_SpaceInRowBetweenButtons) * this.m_BoardViewColSize;
        width += k_Left + k_SpaceInRowBetweenButtons;
        this.ClientSize = new System.Drawing.Size(width, height);
    }

    private void setScoreBoardSize()
    {
        this.LabelPlayer1 = new System.Windows.Forms.Label();
        this.LabelPlayer2 = new System.Windows.Forms.Label();
        this.LabelPlayer2Score = new System.Windows.Forms.Label();
        this.LabelPlayer1Score = new System.Windows.Forms.Label();
        //// 
        //// LabelPlayer1
        //// 
        this.LabelPlayer1.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
        this.LabelPlayer1.AutoSize = true;
        int HeightPlayer1 = ClientSize.Height - 20;
        int WidthPlayer1 = ClientSize.Width - ((ClientSize.Width / 4) * 3);
        this.LabelPlayer1.Location = new System.Drawing.Point(WidthPlayer1, HeightPlayer1);
        this.LabelPlayer1.Name = "LabelPlayer1";
        this.LabelPlayer1.Size = new System.Drawing.Size(71, 13);
        this.LabelPlayer1.TabIndex = 0;
        this.LabelPlayer1.Text = "LabelPlayer1:";
        //// 
        //// LabelPlayer1Score
        //// 
        this.LabelPlayer1Score.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
        this.LabelPlayer1Score.AutoSize = true;
        this.LabelPlayer1Score.Location = new System.Drawing.Point(WidthPlayer1 + 71, HeightPlayer1);
        this.LabelPlayer1Score.Name = "LabelPlayer1Score";
        this.LabelPlayer1Score.Size = new System.Drawing.Size(13, 13);
        this.LabelPlayer1Score.TabIndex = 2;
        this.LabelPlayer1Score.Text = "0";
         //// 
        //// LabelPlayer2
        //// 
        this.LabelPlayer2.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
        this.LabelPlayer2.AutoSize = true;
        int HeightPlayer2 = HeightPlayer1;
        int WidthPlayer2 = ClientSize.Width - (WidthPlayer1 * 2);
        this.LabelPlayer2.Location = new System.Drawing.Point(WidthPlayer2, HeightPlayer2);
        this.LabelPlayer2.Name = "LabelPlayer2";
        this.LabelPlayer2.Size = new System.Drawing.Size(71, 13);
        this.LabelPlayer2.TabIndex = 1;
        this.LabelPlayer2.Text = "LabelPlayer2:";
        //// 
        //// LabelPlayer2Score
        //// 
        this.LabelPlayer2Score.Anchor = System.Windows.Forms.AnchorStyles.Bottom;
        this.LabelPlayer2Score.AutoSize = true;
        this.LabelPlayer2Score.Location = new System.Drawing.Point(WidthPlayer2 + 71,  HeightPlayer2);
        this.LabelPlayer2Score.Name = "LabelPlayer2Score";
        this.LabelPlayer2Score.Size = new System.Drawing.Size(13, 13);
        this.LabelPlayer2Score.TabIndex = 3;
        this.LabelPlayer2Score.Text = "0";
        
        this.Controls.Add(this.LabelPlayer2Score);
        this.Controls.Add(this.LabelPlayer1Score);
        this.Controls.Add(this.LabelPlayer2);
        this.Controls.Add(this.LabelPlayer1);
    }

    private void initializeComponent()
    {
            this.SuspendLayout();
            //// 
            //// FormGamePlay
            //// 
            this.AutoSize = true;
            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
            this.Name = "FormGamePlay";
            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
            this.Text = "4 In A Row";
            this.ResumeLayout(false);
    }

    private void loadBoardButtons(int i_RowSize, int i_ColSize)
    {
        Cell[,] BoardCellsMatrix = this.m_GameEngine.BoardMatrix;

        for (int CurrentRow = 0; CurrentRow < i_RowSize; CurrentRow++)
        {
            for (int CurrentCol = 0; CurrentCol < i_ColSize; CurrentCol++)
            {
                BoardButton CurrentBoardButton = new BoardButton();
                CurrentBoardButton.Top = ((CurrentBoardButton.Height + k_SpaceInRowBetweenButtons) * CurrentRow) + this.r_ColumnNumberedButtonsList[CurrentCol].Height + this.r_ColumnNumberedButtonsList[CurrentCol].Top + k_SpaceInRowBetweenButtons;
                CurrentBoardButton.Parent = this;
                CurrentBoardButton.Left = this.r_ColumnNumberedButtonsList[CurrentCol].Left;

                this.Controls.Add(CurrentBoardButton);
                this.r_BoardButtonsArray[CurrentRow, CurrentCol] = CurrentBoardButton;
            }
        }
    }

    private void loadColsButtons(int i_ColSize)
    {
        int left = k_Left;

        for (int CurrentColIndex = 1; CurrentColIndex <= i_ColSize; CurrentColIndex++)
        {
            ColumnNumberedButton CurrentColButton = new ColumnNumberedButton(CurrentColIndex);
            CurrentColButton.Top = k_Left;
            CurrentColButton.Left = left;
            CurrentColButton.Parent = this;
            CurrentColButton.TabIndex = CurrentColIndex;
            left += CurrentColButton.Width + k_SpaceInRowBetweenButtons;

            CurrentColButton.Click += new EventHandler(this.OnButtonClick);

            this.Controls.Add(CurrentColButton);
            this.r_ColumnNumberedButtonsList.Add(CurrentColButton);
        }
    }

    private void OnButtonClick(object i_Object, EventArgs i_EventArgs)
    {
        ColumnNumberedButton ClickedButton = i_Object as ColumnNumberedButton;

        int ChosenCol = ClickedButton.TabIndex;

        this.m_CurrentGameStatus = this.m_GameEngine.AddDisc(ChosenCol, (int)this.m_CurrentPlayerIndex);

        this.handleGameStatus(ClickedButton);
    }

    private void handleGameStatus(ColumnNumberedButton i_ClickedButton)
    {
        switch (this.m_CurrentGameStatus)
        {
            case GameEngine.eGameMoveStatus.PlayerWin:
                {
                    this.m_GameEngine.UpdateWinnerScore((int)this.m_CurrentPlayerIndex);
                    this.showPopup();
                    break;
                }

            case GameEngine.eGameMoveStatus.BoardIsFull:
                {
                    this.showPopup();
                    break;
                }

            case GameEngine.eGameMoveStatus.ColumnIsFull:
                {
                    i_ClickedButton.Enabled = false;
                    this.handleCurrentPlayerIndex();
                    this.handlePcPlayerMove();
                    break;
                }

            case GameEngine.eGameMoveStatus.Continue:
                {
                    this.handleCurrentPlayerIndex();
                    this.handlePcPlayerMove();
                    break;
                }
        }
    }

    private void handlePcPlayerMove()
    {
        if (!this.m_IsTwoUserPlayers && this.m_CurrentPlayerIndex.Equals(GameEngine.ePlayerIndex.SecondPlayer))
        {
            Random r = new Random();

            int ChosenColumn = r.Next(1, this.r_ColumnNumberedButtonsList.Count);
            ColumnNumberedButton ChosenColumnNumberedButton = this.r_ColumnNumberedButtonsList[ChosenColumn];

            this.OnButtonClick(ChosenColumnNumberedButton, EventArgs.Empty);
        }
    }

    private void showPopup()
    {
        string PopupQuestion = string.Empty;
        string PopupTitle = string.Empty;

        this.getPopupDetails(ref PopupQuestion, ref PopupTitle);

        if (MessageBox.Show(PopupQuestion, PopupTitle, MessageBoxButtons.YesNo, MessageBoxIcon.Information) == DialogResult.Yes)
        {
            this.initializeNewGame();
        }
        else
        {
            this.finishGame();
        }
    }

    private void initializeNewGame()
    {
        this.m_CurrentPlayerIndex = GameEngine.ePlayerIndex.FirstPlayer;
        this.m_CurrentGameStatus = GameEngine.eGameMoveStatus.Continue;
        this.m_GameEngine.MakeEmptyBoard();
        this.m_GameEngine.DiscsCounter = 0;
        this.resetAllButtons();
    }

    private void resetAllButtons()
    {
        foreach (ColumnNumberedButton CurrentColumnNumberedNumber in this.r_ColumnNumberedButtonsList)
        {
            CurrentColumnNumberedNumber.Enabled = true;
        }

        foreach (BoardButton CurrentBoardButton in this.r_BoardButtonsArray)
        {
            CurrentBoardButton.Text = string.Empty;
        }
    }

    private void getPopupDetails(ref string io_PopupQuestion, ref string io_PopupTitle)
    {
        switch (this.m_CurrentGameStatus)
        {
            case GameEngine.eGameMoveStatus.PlayerWin:
                {
                    io_PopupQuestion = this.getWinnerAnnounce();
                    io_PopupTitle = "A Win!!";
                    break;
                }

            case GameEngine.eGameMoveStatus.BoardIsFull:
                {
                    io_PopupQuestion = string.Format(
@"Tie!!
Another Round?");
                    io_PopupTitle = "A Tie!!";
                    break;
                }
        }
    }

    public void finishGame()
    {
        this.DialogResult = DialogResult.OK;
        this.Close();
    }

    private string getWinnerAnnounce()
    {
        string result = string.Empty;

        string PlayerName = this.getPlayerNameByIndex(this.m_CurrentPlayerIndex);
        result = string.Format(
@"{0} Won!!
Another Round?",
               PlayerName);

        return result;
    }

    private string getPlayerNameByIndex(GameEngine.ePlayerIndex currentPlayer)
    {
        string result = string.Empty;
        if (((int)currentPlayer + 1) == 1)
        {
            result = this.LabelPlayer1.Text;
        }
        else if (((int)currentPlayer + 1) == 2)
        {
            result = this.LabelPlayer2.Text;
        }

        return result;
    }

    private void handleCurrentPlayerIndex()
    {
        if (this.m_CurrentPlayerIndex.Equals(GameEngine.ePlayerIndex.FirstPlayer))
        {
            this.m_CurrentPlayerIndex = GameEngine.ePlayerIndex.SecondPlayer;
        }
        else
        {
            this.m_CurrentPlayerIndex = GameEngine.ePlayerIndex.FirstPlayer;
        }
    }
}
